﻿using Nop.Core;
using Nop.Core.Data;
using Nop.Core.Domain.Customers;
using Nop.Core.Plugins;
using Nop.Plugin.ExternalJS.Facebook.Models;
using Nop.Services.Authentication;
using Nop.Services.Common;
using Nop.Services.Configuration;
using Nop.Services.Customers;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Security;
using Nop.Web.Framework.Controllers;
using System;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Nop.Plugin.ExternalJS.Facebook.Controllers
{
    public class ExternalJSFacebookController : Controller
    {
        private readonly ISettingService _settingService;
        private readonly IPermissionService _permissionService;
        private readonly IPluginFinder _pluginFinder;
        private readonly ILocalizationService _localizationService;
        private readonly IRepository<ExternalAuthenticationRecord> _externalAuthenticationRecordRepository;
        private readonly IWorkContext _workContext;
        private readonly ICustomerService _customerService;
        private readonly ICustomerActivityService _customerActivityService;
        private readonly IAuthenticationService _authenticationService;
        private readonly ICustomerRegistrationService _customerRegistrationService;
        private readonly CustomerSettings _customerSettings;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly ILogger _logger;

        public ExternalJSFacebookController(ISettingService settingService,
            IPermissionService permissionService, IWorkContext workContext,
            IPluginFinder pluginFinder,ILocalizationService localizationService,
            IRepository<ExternalAuthenticationRecord> externalAuthenticationRecordRepository,
            ICustomerService customerService, ICustomerActivityService customerActivityService,
            IAuthenticationService authenticationService, ICustomerRegistrationService customerRegistrationService,
            CustomerSettings customerSettings, IGenericAttributeService genericAttributeService, ILogger logger)
        {
            this._settingService = settingService;
            this._permissionService = permissionService;
            this._pluginFinder = pluginFinder;
            this._workContext = workContext;
            this._localizationService = localizationService;
            this._externalAuthenticationRecordRepository = externalAuthenticationRecordRepository;
            this._customerService = customerService;
            this._customerActivityService = customerActivityService;
            this._authenticationService = authenticationService;
            this._customerRegistrationService = customerRegistrationService;
            this._customerSettings = customerSettings;
            this._genericAttributeService = genericAttributeService;
            this._logger = logger;
        }
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods))
                return Content("Access denied");
            //load settings
            var facebookExternalJSSettings = _settingService.LoadSetting<FacebookExternalJSSettings>();
            var model = new ConfigurationModel();
            model.ClientKeyIdentifier = facebookExternalJSSettings.ClientKeyIdentifier;
            model.ClientSecret = facebookExternalJSSettings.ClientSecret;
            return View("Nop.Plugin.ExternalJS.Facebook.Views.ExternalJSFacebook.Configure", model);
        }
        [HttpPost]
        [AdminAuthorize]
        [ChildActionOnly]
        public ActionResult Configure(ConfigurationModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods))
                return Content("Access denied");
            if (!ModelState.IsValid)
                return Configure();

            //load setting 
            var facebookExternalJSSettings = _settingService.LoadSetting<FacebookExternalJSSettings>();

            //save settings
            facebookExternalJSSettings.ClientKeyIdentifier = model.ClientKeyIdentifier;
            facebookExternalJSSettings.ClientSecret = model.ClientSecret;

            _settingService.SaveSetting<FacebookExternalJSSettings>(facebookExternalJSSettings);
            //now clear settings cache
            _settingService.ClearCache();
            //SuccessNotification(_localizationService.GetResource("Admin.Plugins.Saved"));
            return Configure();
        }

        [ChildActionOnly]
        public ActionResult PublicInfo()
        {
            var facebookExternalJSSettings = _settingService.LoadSetting<FacebookExternalJSSettings>();
            //should be load facebookExternalJSSetting setting 
            return View("Nop.Plugin.ExternalJS.Facebook.Views.ExternalJSFacebook.PublicInfo", facebookExternalJSSettings);
        }

        public ActionResult Login(string returnUrl)
        {
            return LoginInternal();
        }
        [HttpPost]
        public ActionResult LoginCallback(CallBackModel model)
        {
            if (VerityParameter(model))
            {
                var externalAuthenticationRecord = new ExternalAuthenticationRecord();
                if (HasLogined(model, out externalAuthenticationRecord))
                {
                    var outModel = new CallbackResult();
                    try
                    {
                        //Get customer 
                        var customer = _customerService.GetCustomerById(externalAuthenticationRecord.CustomerId);
                        _workContext.CurrentCustomer = customer;
                        //login
                        _authenticationService.SignIn(_workContext.CurrentCustomer, false);
                        //log activity
                        _customerActivityService.InsertActivity("Logistics.Login", _localizationService.GetResource("ActivityLog.PublicStore.Login"), customer);

                        outModel = new CallbackResult() { Status = 1, Message = "Success", ReturnURL = GetReturnUrl(model.ReturnUrl) };
                        //return RedirectURL
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex.Message, ex);
                    }
                    return Json(outModel);

                }
                else
                {
                    //Add externalTable 
                    externalAuthenticationRecord = new ExternalAuthenticationRecord
                    {
                        CustomerId = _workContext.CurrentCustomer.Id,
                        ExternalIdentifier = model.Id,
                        OAuthAccessToken = model.AccessToken,
                        ProviderSystemName = "ExternalJS.Facebook",
                        Email = ""
                    };
                    _externalAuthenticationRecordRepository.Insert(externalAuthenticationRecord);
                    var userLoggedIn = _workContext.CurrentCustomer.IsRegistered() ? _workContext.CurrentCustomer : null;
                    //Register Customer
                    bool isApproved = _customerSettings.UserRegistrationType == UserRegistrationType.Standard;
                    var currentCustomer = _workContext.CurrentCustomer;
                    var randomPassword = CommonHelper.GenerateRandomDigitCode(20);
                    currentCustomer.CreatedOnUtc = DateTime.UtcNow;
                    currentCustomer.Password = randomPassword;
                    currentCustomer.PasswordFormatId = 1;
                    currentCustomer.StoreId = 1;
                    currentCustomer.Email = GetRandomEmail(model.Id);
                    //var registrationRequest = new CustomerRegistrationRequest(currentCustomer, ,
                    //    _customerSettings.UsernamesEnabled ? model.RegisterModel.Username : model.RegisterModel.Email,
                    //    model.RegisterModel.Password, _customerSettings.DefaultPasswordFormat, true, _customerSettings.EnableFreeMembership);
                    //var registrationResult = _customerRegistrationService.RegisterCustomer(registrationRequest);
                    //_customerRegistrationService.RegisterCustomer()
                    var registrationRequest = new CustomerRegistrationRequest(currentCustomer, currentCustomer.Email,
                        _customerSettings.UsernamesEnabled ? currentCustomer.Username : currentCustomer.Email, randomPassword, PasswordFormat.Clear, isApproved, _customerSettings.EnableFreeMembership);
                    var registrationResult = _customerRegistrationService.RegisterCustomer(registrationRequest);
                    if (registrationResult.Success)
                    {
                        var fullNames = model.Name.Split(' ');
                        var firstName = fullNames[0];
                        var lastName = fullNames[1];
                        if (fullNames.Count() > 1)
                        {
                            //store other parameters (form fields)
                            if (!String.IsNullOrEmpty(firstName))
                                _genericAttributeService.SaveAttribute(currentCustomer, SystemCustomerAttributeNames.FirstName, firstName);
                            if (!String.IsNullOrEmpty(lastName))
                                _genericAttributeService.SaveAttribute(currentCustomer, SystemCustomerAttributeNames.LastName, lastName);
                        }
                        //login
                        _authenticationService.SignIn(_workContext.CurrentCustomer, false);
                        //log activity
                        _customerActivityService.InsertActivity("Logistics.Login", _localizationService.GetResource("ActivityLog.PublicStore.Login"), currentCustomer);
 
                        var outModel = new CallbackResult() { Status = 1, Message = "Success", ReturnURL = GetReturnUrl(model.ReturnUrl) };
                        return Json(outModel);
                    }
                    else
                    {
                        return Json(new CallbackResult() { Status = 0, Message = "RegisterError" });
                    }
                }
            }
            else
            {
                return Json(new CallbackResult() { Status = 0, Message = "Error" });
            }
        }
        public ActionResult LoginInternal()
        {
            return View();
        }
        private bool VerityParameter(CallBackModel model)
        {
            if (String.IsNullOrEmpty(model.Id) || string.IsNullOrEmpty(model.Name) || string.IsNullOrEmpty(model.AccessToken))
                return false;
            return true;
        }
        private bool HasLogined(CallBackModel model,out ExternalAuthenticationRecord ext)
        {
            ext = _externalAuthenticationRecordRepository.Table
               .Where(o => o.ExternalIdentifier == model.Id && o.ProviderSystemName == "ExternalJS.Facebook")
               .FirstOrDefault();
            if (ext != null)
                return true;
            return false;
        }
        private string GetReturnUrl(string modelReturnUrl)
        {
            //if (string.IsNullOrEmpty(modelReturnUrl))
            //    return _settingService.GetSettingByKey("homePageUrl").Value;
            //else 
            //{
            //    var test = new Uri(modelReturnUrl);
            //    return (HttpUtility.UrlDecode(test.Query.Replace("?ReturnUrl=", "")));
            //}
            return _settingService.GetSettingByKey("homePageUrl").Value;
        }
        private string GetRandomEmail(string id)
        {
            if (string.IsNullOrEmpty(id))
                id = "999999";
            //to-do:add the get face book login email Function in the plugin
            StringBuilder strEmailBuilder = new StringBuilder(DateTime.UtcNow.ToString("yyyymmddhhmmssfff")).Append(id.Substring(0,5)).Append("@ExternalJS.Facebook.com");
            return strEmailBuilder.ToString();
        }
    }
}
